package com.coolxiaoyao.web.http;

import com.coolxiaoyao.common.context.AbstractNtApplicationContext;
import com.coolxiaoyao.common.exception.HttpMethodNotAllowException;
import com.coolxiaoyao.common.exception.HttpNotFoundException;
import com.coolxiaoyao.common.http.HttpMethod;
import com.coolxiaoyao.common.inner.UrlInnerExchange;
import com.coolxiaoyao.common.mapping.UrlMapping;
import com.coolxiaoyao.web.converter.ObjectConverter;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;


/**
 * @author Kerry on 18/09/19
 */

public class DispatcherServlet {

    private static Logger logger = LoggerFactory.getLogger(DispatcherServlet.class);

    private HttpHeaderFilter httpHeaderFilter;
    private AbstractNtApplicationContext applicationContext;
    private ObjectConverter objectConverter;
    private Filter filter;


    public DispatcherServlet(AbstractNtApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        objectConverter = new ObjectConverter();
    }

    public Object dispatcher(FullHttpRequest request) throws Exception {

        logger.trace("{}", request);

        // Http Header 处理
        HttpHeaders headers = request.headers();
        if (httpHeaderFilter != null) {
            httpHeaderFilter.filter(headers);
        }

        if (filter != null) {
            return filter.filter(headers);
        }

        HttpMethod httpMethod = HttpMethod.fromType(request.method().name());


        String uri = request.uri();
        QueryStringDecoder params = new QueryStringDecoder(uri);

        // 匹配URL
        UrlInnerExchange exchange = applicationContext.matchUrlMapping(params.rawPath());
        if (exchange == null) {
            throw new HttpNotFoundException(uri);
        }

        // 匹配方法
        UrlMapping urlMapping = exchange.getUrlMappingMap().get(httpMethod);
        if (urlMapping == null) {
            throw new HttpMethodNotAllowException(uri);
        }

        // RequestBody
        ByteBuf content = request.content();
        byte[] steam = new byte[content.readableBytes()];
        content.readBytes(steam);
        ReferenceCountUtil.refCnt(content);

        // 执行方法的的参数类型
        Class<?>[] paramTypes = urlMapping.getParamTypes();
        // 执行方法
        Method method = urlMapping.getMethod();
        // 执行方法参数注解
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();

        // 参数类型转换处理
        Object[] convert = objectConverter.getObjectParams(paramTypes, parameterAnnotations, params, steam, exchange);

        // 执行处理
        return method.invoke(urlMapping.getController(), convert);
    }


    public AbstractNtApplicationContext getApplicationContext() {
        return applicationContext;
    }


    public Filter getFilter() {
        return filter;
    }

    public void setFilter(Filter filter) {
        this.filter = filter;
    }

    public void setHttpHeaderFilter(HttpHeaderFilter chainFilter) {
        this.httpHeaderFilter = chainFilter;
    }
}
